﻿#region Copyright and Licensing Notice
// Copyright (C) 2011 Steven Bosnick
// 
// This program is open source software; you can redistribute it 
// and/or modifiy it under the terms of the Eclipse Public License,
// version 1.0.
// 
// This program is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied
// warranty of MERCHANTABILITY or FITNESS FOR A 
// PARTICULAR PURPOSE. See the Eclipse Public License for more
// details.
// 
// You should have received a copy of the Eclipse Public License 
// along with this program; if not, you can find a copy at
// "http://www.opensource.org/licenses/eclipse-1.0.php".
#endregion
using System;

namespace BitwiseOre.SharedMemory.Core.Primatives
{
    internal struct CountedIndex : IEquatable<CountedIndex>
    {
        private const int NumIndexBits = 12;
        private const int NumUint32Bits = 8 * sizeof(uint);
        private const int NumCountBits = NumUint32Bits - NumIndexBits;
        private const uint IndexMask = ~0u >> NumCountBits;
        private const uint CountMask = ~0u << NumIndexBits;
        public const int MaxIndex = unchecked((int)IndexMask);

        private readonly uint _data;

        public CountedIndex(int index, int count)
        {
            if (index < 0 || index > IndexMask) throw new ArgumentOutOfRangeException("index");

            unchecked
            {
                var uindex = (uint) index;
                var ucount = (uint) count;

                _data = (uindex & IndexMask) | ((ucount << NumIndexBits) & CountMask);
            }
        }

        private CountedIndex(uint data)
        {
            _data = data;
        }

        public int Index { get { return unchecked((int) (_data & IndexMask)); } }
        public int Count { get { return unchecked((int) ((_data & CountMask) >> NumIndexBits)); } }

        public bool Equals(CountedIndex other)
        {
            return other._data == _data;
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            return obj.GetType() == typeof (CountedIndex) && Equals((CountedIndex) obj);
        }

        public override int GetHashCode()
        {
            return _data.GetHashCode();
        }

        public static bool operator ==(CountedIndex left, CountedIndex right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(CountedIndex left, CountedIndex right)
        {
            return !left.Equals(right);
        }

        public override string ToString()
        {
            return string.Format("Index = {0}, Count = {1}", Index, Count);
        }

        public static implicit operator int(CountedIndex countedIndex)
        {
            return unchecked((int) countedIndex._data);
        }

        public static explicit operator CountedIndex(int data)
        {
            return unchecked(new CountedIndex((uint) data));
        }

    }
}